package com.wiscamp.ninechapters.tags.application.services;

import com.wiscamp.ninechapters.common.core.CollectionHelper;
import com.wiscamp.ninechapters.tags.application.assemblers.KnowledgePointAssembler;
import com.wiscamp.ninechapters.tags.application.dto.command.*;
import com.wiscamp.ninechapters.tags.application.dto.vo.KnowledgePointRelationVO;
import com.wiscamp.ninechapters.tags.application.dto.vo.KnowledgePointVO;
import com.wiscamp.ninechapters.tags.application.dto.vo.KnowledgeTreePointVO;
import com.wiscamp.ninechapters.tags.domain.repositories.KnowledgePointRepository;
import com.wiscamp.ninechapters.tags.domain.services.KnowledgePointService;
import cube.ddd.application.BaseAppService;
import cube.ddd.application.command.DeleteCommand;
import cube.ddd.application.command.DisableCommand;
import cube.ddd.application.command.EnableCommand;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.utils.AppServiceUtils;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;

import java.util.Collection;

@Service
public class KnowledgePointAppService extends BaseAppService {

    private final KnowledgePointRepository knowledgePointRepository;

    private final KnowledgePointService knowledgePointService;

    public KnowledgePointAppService(KnowledgePointRepository knowledgePointRepository, KnowledgePointService knowledgePointService) {
        this.knowledgePointRepository = knowledgePointRepository;
        this.knowledgePointService = knowledgePointService;
    }

    // region knowledgePoint
    @HandleServiceException
    public KnowledgePointVO getKnowledgePoint(@Min(0) long pointId) {
        return AppServiceUtils.getById(pointId, knowledgePointService::getKnowledgePoint,
                KnowledgePointAssembler.Instance::toKnowledgePointVO);
    }

    @HandleServiceException
    public KnowledgePointVO getKnowledgePointByCode(@NotBlank String pointCode, @Min(0) long subjectId) {
        return AppServiceUtils.getByTextAndId(pointCode, subjectId, knowledgePointRepository::getKnowledgePointByCode,
                KnowledgePointAssembler.Instance::toKnowledgePointVO);
    }

    @HandleServiceException
    public Collection<KnowledgePointVO> getKnowledgePointsByName(@NotBlank String pointName, @Min(0) long subjectId) {
        return AppServiceUtils.getListByTextAndId(pointName, subjectId, knowledgePointRepository::getKnowledgePointsByName,
                KnowledgePointAssembler.Instance::toKnowledgePointVO);
    }

    @HandleServiceException
    public KnowledgePointVO getFirstKnowledgePointByName(@NotBlank String pointName, @Min(0) long subjectId) {
        return AppServiceUtils.getByTextAndId(pointName, subjectId, knowledgePointRepository::getFirstKnowledgePointByName,
                KnowledgePointAssembler.Instance::toKnowledgePointVO);
    }

    @HandleServiceException
    public Collection<KnowledgePointVO> getKnowledgePointsBySubject(@Min(0) long subjectId) {
        return AppServiceUtils.getListById(subjectId, knowledgePointRepository::getKnowledgePointsBySubject,
                KnowledgePointAssembler.Instance::toKnowledgePointVO);
    }

    @HandleServiceException
    public Collection<Long> getKnowledgePointIdsBySubject(@Min(0) long subjectId) {
        return knowledgePointRepository.getKnowledgePointIdsBySubject(subjectId);
    }

    @HandleServiceException
    public Collection<KnowledgePointVO> getKnowledgePointsByNameContains(@NotBlank String name, @Min(0) long subjectId) {
        return AppServiceUtils.getListByTextAndId(name, subjectId, knowledgePointRepository::getKnowledgePointsByNameContains,
                KnowledgePointAssembler.Instance::toKnowledgePointVO);
    }

    @HandleServiceException
    public Collection<KnowledgePointVO> getKnowledgePointsByIds(@NotBlank Collection<Long> pointIds) {
        return AppServiceUtils.getListByIds(pointIds, knowledgePointRepository::getKnowledgePointsByIds,
                KnowledgePointAssembler.Instance::toKnowledgePointVO);
    }

    @HandleServiceException
    public Collection<KnowledgePointVO> getRandomKnowledgePoints(@Min(0) long subjectId, int quantity) {
        var points = knowledgePointRepository.getRandomKnowledgePoints(subjectId, quantity);
        return CollectionHelper.convertToArrayList(points, KnowledgePointAssembler.Instance::toKnowledgePointVO);
    }

    @HandleServiceException
    public KnowledgePointVO createKnowledgePoint(@NotNull CreateKnowledgePointCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), knowledgePointService::createKnowledgePoint,
                KnowledgePointAssembler.Instance::toKnowledgePointVO,
                KnowledgePointAssembler.Instance::fromCreateCommand);
    }

    @HandleServiceException
    public KnowledgePointVO updateKnowledgePoint(@NotNull UpdateKnowledgePointCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), knowledgePointService::updateKnowledgePoint,
                KnowledgePointAssembler.Instance::toKnowledgePointVO,
                KnowledgePointAssembler.Instance::fromUpdateCommand);
    }

    @HandleServiceException
    public boolean deleteKnowledgePoint(@NotNull DeleteCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), knowledgePointService::deleteKnowledgePoint);
    }

    @HandleServiceException
    public boolean enableKnowledgePoint(@NotNull EnableCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.enable(command.getId(), command.getOperatorId(), knowledgePointService::enableKnowledgePoint);
    }

    @HandleServiceException
    public boolean disableKnowledgePoint(@NotNull DisableCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.disable(command.getId(), command.getOperatorId(), knowledgePointService::disableKnowledgePoint);
    }
    // endregion


    // region knowledgePoint Relation
    @HandleServiceException
    public KnowledgePointRelationVO getKnowledgePointRelation(@Min(0) long id) {
        return AppServiceUtils.getById(id, knowledgePointRepository::getKnowledgePointRelation,
                KnowledgePointAssembler.Instance::toKnowledgePointRelationVO);
    }

    @HandleServiceException
    public Collection<KnowledgePointRelationVO> getKnowledgePointRelationsBySource(@Min(0) long sourceId) {
        return AppServiceUtils.getListById(sourceId, knowledgePointRepository::getKnowledgePointRelationsBySource,
                KnowledgePointAssembler.Instance::toKnowledgePointRelationVO);
    }

    @HandleServiceException
    public Collection<Long> getChildKnowledgePointIds(@NotBlank Collection<Long> pointIds) {
        return knowledgePointRepository.getChildKnowledgePointIds(pointIds);
    }

    @HandleServiceException
    public Collection<KnowledgePointRelationVO> getNonAggregationRelationsByPoint(@Min(0) long sourceId) {
        return AppServiceUtils.getListById(sourceId, knowledgePointRepository::getNonAggregationRelationsBySource,
                KnowledgePointAssembler.Instance::toKnowledgePointRelationVO);
    }


    @HandleServiceException
    public KnowledgePointRelationVO createKnowledgePointRelation(@NotNull CreateKnowledgePointRelationCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), knowledgePointService::createKnowledgePointRelation,
                KnowledgePointAssembler.Instance::toKnowledgePointRelationVO,
                KnowledgePointAssembler.Instance::fromCreateCommand);
    }

    @HandleServiceException
    public KnowledgePointRelationVO updateKnowledgePointRelation(@NotNull UpdateKnowledgePointRelationCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), knowledgePointService::updateKnowledgePointRelation,
                KnowledgePointAssembler.Instance::toKnowledgePointRelationVO,
                KnowledgePointAssembler.Instance::fromUpdateCommand);
    }

    @HandleServiceException
    public boolean deleteKnowledgePointRelation(@NotNull DeleteCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), knowledgePointService::deleteKnowledgePointRelation);
    }
    // endregion


    // region knowledgePoint tree
    @HandleServiceException
    public Collection<KnowledgeTreePointVO> getKnowledgeTreePointsBySubject(@Min(0) long subjectId) {
        return AppServiceUtils.getListById(subjectId, knowledgePointRepository::getKnowledgeTreePointsBySubject,
                KnowledgePointAssembler.Instance::toKnowledgeTreePointVO);
    }

    @HandleServiceException
    public Collection<KnowledgeTreePointVO> getKnowledgeTreePointsByParent(@Min(0) long subjectId, @Min(0) long parentId) {
        return AppServiceUtils.getListByIdAndId(subjectId, parentId, knowledgePointRepository::getKnowledgeTreePointsByParent,
                KnowledgePointAssembler.Instance::toKnowledgeTreePointVO);
    }

    @HandleServiceException
    public boolean arrangeChildKnowledgePoints(@NotNull ArrangeKnowledgeTreePointCommand command) {
        command.setOperatorId(getCurrentUserId());
        return knowledgePointService.arrangeChildKnowledgePoints(command.getParentPointId(), command.getPointLevel(), command.getOperatorId());
    }

    @HandleServiceException
    public boolean moveKnowledgeTreePoint(@NotNull MoveKnowledgeTreePointCommand command) {
        command.setOperatorId(getCurrentUserId());
        return knowledgePointService.moveKnowledgeTreePoint(command.getPointId(), command.getParentPointId(),
                command.getTargetParentPointId(), command.getOperatorId());
    }
    // endregion
}
